home *** CD-ROM | disk | FTP | other *** search
- Subject: v21i007: Find files using C expressions, Part02/02
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Kenneth Stauffer <cpsc.UCalgary.CA!stauffer>
- Posting-number: Volume 21, Issue 7
- Archive-name: rh2/part02
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 2 (of 2)."
- # Contents: getopt.c rhparse.c
- # Wrapped by rsalz@litchi.bbn.com on Wed Feb 7 15:35:30 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'getopt.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'getopt.c'\"
- else
- echo shar: Extracting \"'getopt.c'\" \(16259 characters\)
- sed "s/^X//" >'getopt.c' <<'END_OF_FILE'
- X
- X#undef _POSIX_OPTION_ORDER
- X
- X/* Getopt for GNU.
- X Modified by David MacKenzie to use malloc and free instead of alloca,
- X and memcpy instead of bcopy under System V.
- X Copyright (C) 1987 Free Software Foundation, Inc.
- X
- X NO WARRANTY
- X
- X BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
- XNO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
- XWHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
- XRICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
- XWITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
- XBUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- XFITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
- XAND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
- XDEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
- XCORRECTION.
- X
- X IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
- XSTALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
- XWHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
- XLIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
- XOTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
- XUSE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
- XDATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
- XA FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
- XPROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
- XDAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
- X
- X GENERAL PUBLIC LICENSE TO COPY
- X
- X 1. You may copy and distribute verbatim copies of this source file
- Xas you receive it, in any medium, provided that you conspicuously and
- Xappropriately publish on each copy a valid copyright notice "Copyright
- X (C) 1987 Free Software Foundation, Inc."; and include following the
- Xcopyright notice a verbatim copy of the above disclaimer of warranty
- Xand of this License. You may charge a distribution fee for the
- Xphysical act of transferring a copy.
- X
- X 2. You may modify your copy or copies of this source file or
- Xany portion of it, and copy and distribute such modifications under
- Xthe terms of Paragraph 1 above, provided that you also do the following:
- X
- X a) cause the modified files to carry prominent notices stating
- X that you changed the files and the date of any change; and
- X
- X b) cause the whole of any work that you distribute or publish,
- X that in whole or in part contains or is a derivative of this
- X program or any part thereof, to be licensed at no charge to all
- X third parties on terms identical to those contained in this
- X License Agreement (except that you may choose to grant more
- X extensive warranty protection to third parties, at your option).
- X
- X c) You may charge a distribution fee for the physical act of
- X transferring a copy, and you may at your option offer warranty
- X protection in exchange for a fee.
- X
- X 3. You may copy and distribute this program or any portion of it in
- Xcompiled, executable or object code form under the terms of Paragraphs
- X1 and 2 above provided that you do the following:
- X
- X a) cause each such copy to be accompanied by the
- X corresponding machine-readable source code, which must
- X be distributed under the terms of Paragraphs 1 and 2 above; or,
- X
- X b) cause each such copy to be accompanied by a
- X written offer, with no time limit, to give any third party
- X free (except for a nominal shipping charge) a machine readable
- X copy of the corresponding source code, to be distributed
- X under the terms of Paragraphs 1 and 2 above; or,
- X
- X c) in the case of a recipient of this program in compiled, executable
- X or object code form (without the corresponding source code) you
- X shall cause copies you distribute to be accompanied by a copy
- X of the written offer of source code which you received along
- X with the copy you received.
- X
- X 4. You may not copy, sublicense, distribute or transfer this program
- Xexcept as expressly provided under this License Agreement. Any attempt
- Xotherwise to copy, sublicense, distribute or transfer this program is void and
- Xyour rights to use the program under this License agreement shall be
- Xautomatically terminated. However, parties who have received computer
- Xsoftware programs from you with this License Agreement will not have
- Xtheir licenses terminated so long as such parties remain in full compliance.
- X
- X 5. If you wish to incorporate parts of this program into other free
- Xprograms whose distribution conditions are different, write to the Free
- XSoftware Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
- Xworked out a simple rule that can be stated here, but we will often permit
- Xthis. We will be guided by the two goals of preserving the free status of
- Xall derivatives of our free software and of promoting the sharing and reuse of
- Xsoftware.
- X
- X
- XIn other words, you are welcome to use, share and improve this program.
- XYou are forbidden to forbid anyone else to use, share and improve
- Xwhat you give them. Help stamp out software-hoarding! */
- X
- X/* This version of `getopt' appears to the caller like standard Unix `getopt'
- X but it behaves differently for the user, since it allows the user
- X to intersperse the options with the other arguments.
- X
- X As `getopt' works, it permutes the elements of `argv' so that,
- X when it is done, all the options precede everything else. Thus
- X all application programs are extended to handle flexible argument order.
- X
- X Setting the environment variable _POSIX_OPTION_ORDER disables permutation.
- X Then the behavior is completely standard.
- X
- X GNU application programs can use a third alternative mode in which
- X they can distinguish the relative order of options and other arguments. */
- X
- X#include <stdio.h>
- X
- X#if SYSV || SYSVR3
- X#define bcopy(s, d, l) memcpy((d), (s), (l))
- X#define index strchr
- X#endif
- X
- X/* For communication from `getopt' to the caller.
- X When `getopt' finds an option that takes an argument,
- X the argument value is returned here.
- X Also, when `ordering' is RETURN_IN_ORDER,
- X each non-option ARGV-element is returned here. */
- X
- Xchar *optarg = 0;
- X
- X/* Index in ARGV of the next element to be scanned.
- X This is used for communication to and from the caller
- X and for communication between successive calls to `getopt'.
- X
- X On entry to `getopt', zero means this is the first call; initialize.
- X
- X When `getopt' returns EOF, this is the index of the first of the
- X non-option elements that the caller should itself scan.
- X
- X Otherwise, `optind' communicates from one call to the next
- X how much of ARGV has been scanned so far. */
- X
- Xint optind = 0;
- X
- X/* The next char to be scanned in the option-element
- X in which the last option character we returned was found.
- X This allows us to pick up the scan where we left off.
- X
- X If this is zero, or a null string, it means resume the scan
- X by advancing to the next ARGV-element. */
- X
- Xstatic char *nextchar;
- X
- X/* Callers store zero here to inhibit the error message
- X for unrecognized options. */
- X
- Xint opterr = 1;
- X
- X/* Describe how to deal with options that follow non-option ARGV-elements.
- X
- X UNSPECIFIED means the caller did not specify anything;
- X the default is then REQUIRE_ORDER if the environment variable
- X _OPTIONS_FIRST is defined, PERMUTE otherwise.
- X
- X REQUIRE_ORDER means don't recognize them as options.
- X Stop option processing when the first non-option is seen.
- X This is what Unix does.
- X
- X PERMUTE is the default. We permute the contents of `argv' as we scan,
- X so that eventually all the options are at the end. This allows options
- X to be given in any order, even with programs that were not written to
- X expect this.
- X
- X RETURN_IN_ORDER is an option available to programs that were written
- X to expect options and other ARGV-elements in any order and that care about
- X the ordering of the two. We describe each non-option ARGV-element
- X as if it were the argument of an option with character code zero.
- X Using `-' as the first character of the list of option characters
- X requests this mode of operation.
- X
- X The special argument `--' forces an end of option-scanning regardless
- X of the value of `ordering'. In the case of RETURN_IN_ORDER, only
- X `--' can cause `getopt' to return EOF with `optind' != ARGC. */
- X
- Xstatic enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering;
- X
- Xchar *malloc ();
- X
- X/* Allocate memory dynamically, with error checking. */
- X
- Xstatic char *
- Xxmalloc (n)
- X unsigned n;
- X{
- X char *p;
- X
- X p = malloc (n);
- X if (!p)
- X {
- X fprintf (stderr, "Virtual memory exhausted\n");
- X exit (1);
- X }
- X return p;
- X}
- X
- X/* Handle permutation of arguments. */
- X
- X/* Describe the part of ARGV that contains non-options that have
- X been skipped. `first_nonopt' is the index in ARGV of the first of them;
- X `last_nonopt' is the index after the last of them. */
- X
- Xstatic int first_nonopt;
- Xstatic int last_nonopt;
- X
- X/* Exchange two adjacent subsequences of ARGV.
- X One subsequence is elements [first_nonopt,last_nonopt)
- X which contains all the non-options that have been skipped so far.
- X The other is elements [last_nonopt,optind), which contains all
- X the options processed since those non-options were skipped.
- X
- X `first_nonopt' and `last_nonopt' are relocated so that they describe
- X the new indices of the non-options in ARGV after they are moved. */
- X
- Xstatic void
- Xexchange (argv)
- X char **argv;
- X{
- X int nonopts_size
- X = (last_nonopt - first_nonopt) * sizeof (char *);
- X char **temp = (char **) xmalloc (nonopts_size);
- X
- X /* Interchange the two blocks of data in argv. */
- X
- X bcopy (&argv[first_nonopt], temp, nonopts_size);
- X bcopy (&argv[last_nonopt], &argv[first_nonopt],
- X (optind - last_nonopt) * sizeof (char *));
- X bcopy (temp, &argv[first_nonopt + optind - last_nonopt],
- X nonopts_size);
- X
- X free (temp);
- X
- X /* Update records for the slots the non-options now occupy. */
- X
- X first_nonopt += (optind - last_nonopt);
- X last_nonopt = optind;
- X}
- X
- X/* Scan elements of ARGV (whose length is ARGC) for option characters
- X given in OPTSTRING.
- X
- X If an element of ARGV starts with '-', and is not exactly "-" or "--",
- X then it is an option element. The characters of this element
- X (aside from the initial '-') are option characters. If `getopt'
- X is called repeatedly, it returns successively each of the option characters
- X from each of the option elements.
- X
- X If `getopt' finds another option character, it returns that character,
- X updating `optind' and `nextchar' so that the next call to `getopt' can
- X resume the scan with the following option character or ARGV-element.
- X
- X If there are no more option characters, `getopt' returns `EOF'.
- X Then `optind' is the index in ARGV of the first ARGV-element
- X that is not an option. (The ARGV-elements have been permuted
- X so that those that are not options now come last.)
- X
- X OPTSTRING is a string containing the legitimate option characters.
- X A colon in OPTSTRING means that the previous character is an option
- X that wants an argument. The argument is taken from the rest of the
- X current ARGV-element, or from the following ARGV-element,
- X and returned in `optarg'.
- X
- X If an option character is seen that is not listed in OPTSTRING,
- X return '?' after printing an error message. If you set `opterr' to
- X zero, the error message is suppressed but we still return '?'.
- X
- X If a char in OPTSTRING is followed by a colon, that means it wants an arg,
- X so the following text in the same ARGV-element, or the text of the following
- X ARGV-element, is returned in `optarg. Two colons mean an option that
- X wants an optional arg; if there is text in the current ARGV-element,
- X it is returned in `optarg'.
- X
- X If OPTSTRING starts with `-', it requests a different method of handling the
- X non-option ARGV-elements. See the comments about RETURN_IN_ORDER, above.
- X */
- X
- Xint
- Xgetopt (argc, argv, optstring)
- X int argc;
- X char **argv;
- X char *optstring;
- X{
- X /* Initialize the internal data when the first call is made.
- X Start processing options with ARGV-element 1 (since ARGV-element 0
- X is the program name); the sequence of previously skipped
- X non-option ARGV-elements is empty. */
- X
- X if (optind == 0)
- X {
- X first_nonopt = last_nonopt = optind = 1;
- X
- X nextchar = 0;
- X
- X /* Determine how to handle the ordering of options and nonoptions. */
- X
- X if (optstring[0] == '-')
- X ordering = RETURN_IN_ORDER;
- X else if (getenv ("_POSIX_OPTION_ORDER") != 0)
- X ordering = REQUIRE_ORDER;
- X else
- X ordering = PERMUTE;
- X }
- X
- X if (nextchar == 0 || *nextchar == 0)
- X {
- X if (ordering == PERMUTE)
- X {
- X /* If we have just processed some options following some non-options,
- X exchange them so that the options come first. */
- X
- X if (first_nonopt != last_nonopt && last_nonopt != optind)
- X exchange (argv);
- X else if (last_nonopt != optind)
- X first_nonopt = optind;
- X
- X /* Now skip any additional non-options
- X and extend the range of non-options previously skipped. */
- X
- X while (optind < argc
- X && (argv[optind][0] != '-'
- X || argv[optind][1] == 0))
- X optind++;
- X last_nonopt = optind;
- X }
- X
- X /* Special ARGV-element `--' means premature end of options.
- X Skip it like a null option,
- X then exchange with previous non-options as if it were an option,
- X then skip everything else like a non-option. */
- X
- X if (optind != argc && !strcmp (argv[optind], "--"))
- X {
- X optind++;
- X
- X if (first_nonopt != last_nonopt && last_nonopt != optind)
- X exchange (argv);
- X else if (first_nonopt == last_nonopt)
- X first_nonopt = optind;
- X last_nonopt = argc;
- X
- X optind = argc;
- X }
- X
- X /* If we have done all the ARGV-elements, stop the scan
- X and back over any non-options that we skipped and permuted. */
- X
- X if (optind == argc)
- X {
- X /* Set the next-arg-index to point at the non-options
- X that we previously skipped, so the caller will digest them. */
- X if (first_nonopt != last_nonopt)
- X optind = first_nonopt;
- X return EOF;
- X }
- X
- X /* If we have come to a non-option and did not permute it,
- X either stop the scan or describe it to the caller and pass it by. */
- X
- X if (argv[optind][0] != '-' || argv[optind][1] == 0)
- X {
- X if (ordering == REQUIRE_ORDER)
- X return EOF;
- X optarg = argv[optind++];
- X return 0;
- X }
- X
- X /* We have found another option-ARGV-element.
- X Start decoding its characters. */
- X
- X nextchar = argv[optind] + 1;
- X }
- X
- X /* Look at and handle the next option-character. */
- X
- X {
- X char c = *nextchar++;
- X char *temp = (char *) index (optstring, c);
- X
- X /* Increment `optind' when we start to process its last character. */
- X if (*nextchar == 0)
- X optind++;
- X
- X if (temp == 0 || c == ':')
- X {
- X if (opterr != 0)
- X {
- X if (c < 040 || c >= 0177)
- X fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
- X argv[0], c);
- X else
- X fprintf (stderr, "%s: unrecognized option `-%c'\n",
- X argv[0], c);
- X }
- X return '?';
- X }
- X if (temp[1] == ':')
- X {
- X if (temp[2] == ':')
- X {
- X /* This is an option that accepts an argument optionally. */
- X if (*nextchar != 0)
- X {
- X optarg = nextchar;
- X optind++;
- X }
- X else
- X optarg = 0;
- X nextchar = 0;
- X }
- X else
- X {
- X /* This is an option that requires an argument. */
- X if (*nextchar != 0)
- X {
- X optarg = nextchar;
- X /* If we end this ARGV-element by taking the rest as an arg,
- X we must advance to the next element now. */
- X optind++;
- X }
- X else if (optind == argc)
- X {
- X if (opterr != 0)
- X fprintf (stderr, "%s: no argument for `-%c' option\n",
- X argv[0], c);
- X c = '?';
- X }
- X else
- X /* We already incremented `optind' once;
- X increment it again when taking next ARGV-elt as argument. */
- X optarg = argv[optind++];
- X nextchar = 0;
- X }
- X }
- X return c;
- X }
- X}
- X
- Xmemcpy(s,d,len)
- Xchar *s,*d;
- Xint len;
- X{
- X while(len--) *d++ = *s++;
- X}
- END_OF_FILE
- if test 16259 -ne `wc -c <'getopt.c'`; then
- echo shar: \"'getopt.c'\" unpacked with wrong size!
- fi
- # end of 'getopt.c'
- fi
- if test -f 'rhparse.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rhparse.c'\"
- else
- echo shar: Extracting \"'rhparse.c'\" \(14503 characters\)
- sed "s/^X//" >'rhparse.c' <<'END_OF_FILE'
- X
- X/* ----------------------------------------------------------------------
- X * FILE: rhparse.c
- X * VERSION: 2
- X * Written by: Ken Stauffer
- X * This contains the parser for the C expressions,
- X * gettoken(), getit() and ungetit() routines.
- X * sectime(), datespec(), expression(), expr(), exp0(), ... , factor()
- X * locatename(), push(), find_macro()
- X *
- X *
- X * ---------------------------------------------------------------------- */
- X
- X#include "rh.h"
- X#include <ctype.h>
- X#include <pwd.h>
- X
- Xstatic int cpos; /* current character position */
- Xstatic int lineno; /* current line number */
- X
- X/* ----------------------------------------------------------------------
- X * getit:
- X * Return the next character, input is obtained from a file or
- X * a string.
- X * If expstr == NULL then input is from the file called 'expfname'
- X * with file pointer 'expfile'.
- X *
- X * If expstr != NULL then input is from the string 'expstr'
- X *
- X */
- X
- Xgetit()
- X{
- X int c;
- X
- X if( expstr ) c = (*expstr) ? *expstr++ : EOF;
- X else c = getc(expfile);
- X
- X if( c == '\n' ) { lineno++; cpos = 0; }
- X cpos++;
- X
- X return(c);
- X}
- X
- X/* ----------------------------------------------------------------------
- X * ungetit:
- X * Unget a char.
- X * A character is ungotten using the same scheme as stated for
- X * getit() for determining where input is comming from.
- X *
- X */
- X
- Xungetit(c)
- Xint c;
- X{
- X if( c == '\n' ) { lineno--; cpos = 1; }
- X else cpos--;
- X if( expstr ) expstr = (c > 0) ? expstr-1 : expstr;
- X else ungetc(c,expfile);
- X}
- X
- X/* ----------------------------------------------------------------------
- X * error:
- X * Print an error message and quit.
- X */
- X
- Xerror(s)
- Xchar *s;
- X{
- X if( expstr )
- X fprintf(stderr,"Command line: ");
- X else
- X fprintf(stderr,"%s: ",expfname);
- X
- X fprintf(stderr,"line: %d, char: %d, %s.\n",lineno,cpos,s);
- X exit(1);
- X}
- X
- X/* ----------------------------------------------------------------------
- X * insertname:
- X * Inserts the symbol named 's' with type 't' and value 'val'
- X * into the symbol table. Return the a pointer to the symbol
- X * table entry. The symbol is inserted into the head of the
- X * linked list. This behavior is relied upon elswhere.
- X *
- X */
- X
- Xstruct symbol *insertname(s,t,val)
- Xchar *s;
- Xint t;
- Xlong val;
- X{
- X char *p,*malloc();
- X struct symbol *sym;
- X
- X sym = (struct symbol *) malloc( sizeof(struct symbol) );
- X if( sym == NULL ) error("no more memory");
- X
- X p = sym->name = malloc( strlen(s)+1 );
- X if( sym->name == NULL ) error("no more memory");
- X while( *p++ = *s++ );
- X sym->type = t;
- X sym->value = val;
- X
- X sym->next = symbols;
- X symbols = sym;
- X
- X return( sym );
- X}
- X
- X/* ----------------------------------------------------------------------
- X * locatename:
- X * Do a linear search for 's' in the linked list symbols.
- X *
- X */
- X
- Xstruct symbol *locatename(s)
- Xchar *s;
- X{
- X struct symbol *p;
- X
- X for(p=symbols; p; p = p->next )
- X if( !strcmp(s,p->name) ) return(p);
- X
- X return(NULL);
- X}
- X
- X/* ----------------------------------------------------------------------
- X * push:
- X * "assemble" the instruction into the StackProgram[] array.
- X *
- X */
- X
- Xpush(func,val)
- Xint (*func)();
- Xlong val;
- X{
- X if( PC >= LENGTH ) error("program to big");
- X StackProgram[PC].func=func;
- X StackProgram[PC++].value=val;
- X}
- X
- X/* ----------------------------------------------------------------------
- X * program:
- X * Parse a program of the form:
- X * <program> ==> <function-list> <expression> EOF
- X * | <function-list> EOF
- X * | <function-list> <expression> ;
- X *
- X * <function-list> ==> <function> <function-list>
- X * | empty
- X */
- X
- Xprogram()
- X{
- X cpos = 0; lineno = 1;
- X
- X token = gettoken();
- X for(;;) {
- X if( token != IDENTIFIER ) break;
- X function();
- X }
- X
- X if( token != EOF ) {
- X startPC = PC;
- X expression();
- X push(NULL,0);
- X }
- X if( token != EOF && token != ';') error("EOF expected");
- X}
- X
- X/* ----------------------------------------------------------------------
- X * function:
- X * parse a function definition. Grammer for a function is:
- X * <function> ==> IDENTIFIER <id-list> { RETURN <expression> ; }
- X *
- X * <id-list> ==> ( <ids> )
- X * | ( )
- X * | empty
- X *
- X * <ids> ==> IDENTIFIER <idtail>
- X *
- X * <idtail> ==> , <ids>
- X * | empty
- X *
- X */
- X
- Xfunction()
- X{
- X struct symbol *s;
- X
- X s = tokensym;
- X tokensym->value = PC;
- X tokensym->type = FUNCTION;
- X tokensym->func = c_func;
- X
- X token = gettoken();
- X
- X push(NULL, idlist() ); /* save number of args for function */
- X
- X if( token != '{' ) error("expected '{'");
- X token = gettoken();
- X
- X if( token != RETURN ) error("expected keyword: return");
- X token = gettoken();
- X
- X expression();
- X
- X if( token != ';' ) error("expected ';'");
- X token = gettoken();
- X
- X push(c_return,StackProgram[s->value].value);
- X
- X /* free up the parameter symbols */
- X while( symbols->type == PARAM ) {
- X s = symbols;
- X symbols = symbols->next;
- X free(s->name);
- X free(s);
- X }
- X
- X if( token != '}' ) error("expected '}'");
- X token = gettoken();
- X}
- X
- X/* ----------------------------------------------------------------------
- X * idlist:
- X * Return the maximum offset obtained in parsing the parameter list.
- X * <id-list> ==> ( <ids> )
- X * | ()
- X * | empty
- X *
- X * <ids> ==> IDENTIFIER <idtail>
- X * <idtail> ==> <ids> , <idtail>
- X * | empty
- X */
- X
- Xidlist()
- X{
- X int offset = 0;
- X
- X if( token == '(' ) token = gettoken();
- X else if( token == '{' ) return(0);
- X else error("expected '(' or '{'");
- X
- X if( token == ')' ) {
- X token = gettoken();
- X return(0);
- X }
- X
- X for(;;) {
- X if( token != IDENTIFIER ) error("identifier expected");
- X tokensym->type = PARAM;
- X tokensym->func = c_param;
- X tokensym->value = offset++;
- X token = gettoken();
- X if( token == ')' ) break;
- X if( token != ',' ) error("expected ')'");
- X token = gettoken();
- X }
- X
- X token = gettoken();
- X return(offset);
- X}
- X
- X/* ----------------------------------------------------------------------
- X * expression:
- X * Parse an expression. (top-level routine)
- X * OPERATOR ?:
- X *
- X */
- X
- Xexpression()
- X{
- X int qm,colon,nop;
- X
- X expr0();
- X if( token == '?' ) {
- X token = gettoken();
- X qm = PC;
- X push(c_qm,0);
- X expression();
- X if( token != ':' ) error("missing ':'");
- X token = gettoken();
- X colon = PC;
- X push(c_colon,0);
- X expression();
- X
- X StackProgram[qm].value = colon;
- X StackProgram[colon].value = PC-1;
- X }
- X}
- X
- X/* OPERATOR || */
- Xexpr0()
- X{
- X expr1();
- X for(;;)
- X if( token == OR ) {
- X token = gettoken();
- X expr1();
- X push(c_or,0);
- X } else break;
- X}
- X
- X/* OPERATOR && */
- Xexpr1()
- X{
- X expr2();
- X for(;;)
- X if( token == AND ) {
- X token = gettoken();
- X expr2();
- X push(c_and,0);
- X } else break;
- X}
- X
- X/* OPERATOR | */
- Xexpr2()
- X{
- X expr3();
- X for(;;)
- X if( token == '|' ) {
- X token = gettoken();
- X expr3();
- X push(c_bor,0);
- X } else break;
- X}
- X
- X/* OPERATOR ^ */
- Xexpr3()
- X{
- X expr4();
- X for(;;)
- X if( token == '^' ) {
- X token = gettoken();
- X expr4();
- X push(c_bxor,0);
- X } else break;
- X}
- X
- X/* OPERATOR & */
- Xexpr4()
- X{
- X expr5();
- X for(;;)
- X if( token == '&' ) {
- X token = gettoken();
- X expr5();
- X push(c_band,0);
- X } else break;
- X}
- X
- X/* OPERATOR == != */
- Xexpr5()
- X{
- X int t;
- X expr6();
- X for(;t=token;)
- X if( t==EQ ) {
- X token = gettoken();
- X expr6();
- X push(c_eq,0);
- X } else if( t==NE ) {
- X token = gettoken();
- X expr6();
- X push(c_ne,0);
- X } else break;
- X}
- X
- X/* OPERATOR < <= > >= */
- Xexpr6()
- X{
- X int t;
- X expr7();
- X for(;t=token;)
- X if( t==LE ) {
- X token = gettoken();
- X expr7();
- X push(c_le,0);
- X } else if( t==GE ) {
- X token = gettoken();
- X expr7();
- X push(c_ge,0);
- X } else if( t=='>' ) {
- X token = gettoken();
- X expr7();
- X push(c_gt,0);
- X } else if( t=='<' ) {
- X token = gettoken();
- X expr7();
- X push(c_lt,0);
- X } else break;
- X}
- X
- X/* OPERATOR << >> */
- Xexpr7()
- X{
- X int t;
- X expr8();
- X for(;t=token;)
- X if( t==SHIFTL ) {
- X token = gettoken();
- X expr8();
- X push(c_lshift,0);
- X } else if( t==SHIFTR ) {
- X token = gettoken();
- X expr8();
- X push(c_rshift,0);
- X } else break;
- X}
- X
- X/* OPERATOR + - */
- Xexpr8()
- X{
- X int t;
- X expr9();
- X for(;t=token;)
- X if( t=='+' ) {
- X token = gettoken();
- X expr9();
- X push(c_plus,0);
- X } else if( t=='-' ) {
- X token = gettoken();
- X expr9();
- X push(c_minus,0);
- X } else break;
- X}
- X
- X/* OPERATOR * / % */
- Xexpr9()
- X{
- X int t;
- X expr10();
- X for(;t=token;)
- X if( t== '*' ) {
- X token = gettoken();
- X expr10();
- X push(c_mul,0);
- X } else if( t== '/' ) {
- X token = gettoken();
- X expr10();
- X push(c_div,0);
- X } else if( t== '%' ) {
- X token = gettoken();
- X expr10();
- X push(c_mod,0);
- X } else break;
- X}
- X
- X/* OPERATOR ~ ! - */
- Xexpr10()
- X{
- X int t;
- X t = token;
- X if( t=='!' ){
- X token = gettoken();
- X expr10();
- X push(c_not,0);
- X } else if( t== '~' ) {
- X token = gettoken();
- X expr10();
- X push(c_bnot,0);
- X } else if( t== '-' ) {
- X token = gettoken();
- X expr10();
- X push(c_uniminus,0);
- X } else factor();
- X}
- X
- X/* ----------------------------------------------------------------------
- X * explist:
- X * argc is the number of arguments expected.
- X * Parse an expression list of the form:
- X * <explist> ==> ( <exps> )
- X * | ( )
- X * | empty
- X *
- X * <exps> ==> <exps> , <expression>
- X * | <expression>
- X *
- X */
- X
- Xexplist( argc )
- X{
- X if( token != '(' && !argc ) return;
- X
- X if( token != '(' ) error("missing '('");
- X token = gettoken();
- X
- X if( !argc && token == ')' ) {
- X token = gettoken();
- X return;
- X }
- X
- X for(;;) {
- X expression();
- X argc--;
- X if( token == ')' ) break;
- X if( token != ',' ) error("missing ','");
- X token = gettoken();
- X }
- X
- X token = gettoken();
- X if( argc ) error("wrong number of arguments");
- X}
- X
- X/* ----------------------------------------------------------------------
- X * factor:
- X * Parse a factor. Could be a number, variable, date, function call or
- X * regular expression string.
- X */
- X
- Xfactor()
- X{
- X long l,datespec();
- X int pc;
- X
- X switch(token) {
- X case '(':
- X token = gettoken();
- X expression();
- X if( token != ')' )
- X error("missing ')'");
- X token = gettoken();
- X break;
- X case NUMBER:
- X push(c_number,tokenval);
- X token = gettoken();
- X break;
- X case FUNCTION:
- X pc = tokensym->value;
- X token = gettoken();
- X explist( StackProgram[ pc ].value );
- X push(c_func,pc);
- X break;
- X case PARAM:
- X push(c_param,tokensym->value);
- X token = gettoken();
- X break;
- X case FIELD:
- X push(tokensym->func,tokenval);
- X token = gettoken();
- X break;
- X case '[':
- X token = gettoken();
- X l=datespec();
- X if( token != ']' )
- X error("missing ']'");
- X token = gettoken();
- X push(c_number,l);
- X break;
- X case STR:
- X push(c_str,tokenval);
- X token = gettoken();
- X break;
- X case IDENTIFIER:
- X error("undefined identifier");
- X default:
- X error("syntax error");
- X }
- X}
- X
- X/* ----------------------------------------------------------------------
- X * sectime:
- X * calculate the number of seconds between January 1, 1970
- X * and year/month/day. Return that value.
- X *
- X */
- X
- X#define leap(d) (((d % 4 == 0) && (d % 100 != 0)) || (d % 400 == 0))
- X#define DAYSEC (3600*24)
- X#define YERSEC (3600*24*365)
- X#define TIME0 1970
- X
- Xlong sectime(year,month,day)
- Xint year,month,day;
- X{
- X
- X static int months[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
- X int yeardays,leapers,x;
- X long seconds;
- X
- X if(month>12 || month<1 || year<TIME0 || day<1 || day>months[month]+
- X (month==2 && leap(year)) )
- X return(-1);
- X
- X yeardays = leapers = 0;
- X
- X for(x=1;x<month;x++)
- X yeardays += months[x];
- X if ((month > 2) && leap(year)) yeardays++;
- X
- X for(x=TIME0; x<year; x++)
- X if(leap(x)) leapers++;
- X
- X seconds = yeardays*DAYSEC+(year-TIME0)*YERSEC+7*3600+
- X leapers*DAYSEC + day*DAYSEC;
- X
- X return(seconds);
- X
- X}
- X
- X/* ----------------------------------------------------------------------
- X * datespec:
- X * parse a date. Return the number of seconds from
- X * some date in 1970, until the specified date.
- X */
- X
- Xlong datespec()
- X{
- X int year,month,day,seconds;
- X
- X if( token != NUMBER ) error("number expected");
- X year = tokenval;
- X token = gettoken();
- X if( token != '/' ) error("missing '/'");
- X token = gettoken();
- X if( token != NUMBER ) error("number expected");
- X month = tokenval;
- X token = gettoken();
- X if( token != '/' ) error("missing '/'");
- X token = gettoken();
- X if( token != NUMBER ) error("number expected");
- X day = tokenval;
- X token = gettoken();
- X
- X if( (seconds = sectime(year,month,day)) < 0 )
- X error("invalid date");
- X
- X return(seconds);
- X}
- X
- X
- X/* ----------------------------------------------------------------------
- X * gettoken:
- X * Return the next token.
- X * global variable: tokenval will contain any extra
- X * attribute associated with the returned token, ie
- X * the VALUE of a number, the index of the string etc...
- X * tokensym will be a pointer to the symbol table entry for
- X * any symbol encountered.
- X *
- X */
- X
- Xgettoken()
- X{
- X char buf[IDLENGTH+1],*bufp=buf;
- X int c,incomment;
- X
- X incomment = 0;
- X c = getit();
- X while( c == ' ' || c == '\t' || c == '\n' || c == '/' || incomment) {
- X if( c == '/' && !incomment) {
- X c = getit();
- X if( c != '*' ) {
- X ungetit(c);
- X c = '/';
- X break;
- X }
- X incomment = 1;
- X } else if( c == '*' ) {
- X c = getit();
- X if( c == '/' ) incomment = 0;
- X }
- X c = getit();
- X }
- X
- X if(c=='0') {
- X tokenval=0;
- X while( ( c=getit() ) >= '0' && c <= '7' ) {
- X tokenval <<= 3;
- X tokenval += c-'0';
- X }
- X if( isdigit(c) ) error("bad octal constant");
- X ungetit(c);
- X return(NUMBER);
- X }
- X
- X if(isdigit(c)) {
- X tokenval=c-'0';
- X while(isdigit( (c=getit()) )) {
- X tokenval *=10;
- X tokenval += c-'0';
- X }
- X ungetit(c);
- X return(NUMBER);
- X }
- X
- X if(isalpha(c)) {
- X int count=0;
- X do {
- X if(count++ < IDLENGTH) *bufp++ = c;
- X c=getit();
- X } while( isalnum(c) );
- X ungetit(c);
- X *bufp='\0';
- X if( (tokensym=locatename(buf)) == NULL ) {
- X tokensym = insertname(buf,IDENTIFIER,0);
- X }
- X tokenval = tokensym->value;
- X return( tokensym->type );
- X }
- X
- X if( c == '"' ) {
- X tokenval=strfree;
- X while( (c=getit()) != '"' ) {
- X if( strfree > STRLEN )
- X error("no more string space");
- X Strbuf[strfree++]= c;
- X }
- X Strbuf[strfree++]='\0';
- X return(STR);
- X }
- X
- X if( c == '=' ) {
- X c=getit();
- X if(c== '=') return(EQ);
- X else {
- X ungetit(c);
- X return('=');
- X }
- X }
- X
- X if( c== '$' ) {
- X int count=0;
- X struct passwd *info,*getpwnam();
- X c=getit();
- X if( c=='$' ) {
- X tokenval = getuid();
- X return( NUMBER );
- X }
- X do {
- X if (count++ < IDLENGTH) *bufp++ = c;
- X c=getit();
- X } while( isalnum(c) );
- X ungetit(c);
- X *bufp='\0';
- X if( (info=getpwnam(buf)) == NULL )
- X error("no such user");
- X tokenval = info->pw_uid;
- X return( NUMBER );
- X }
- X
- X if( c == '!' ) {
- X c=getit();
- X if( c == '=' ) return(NE);
- X ungetit(c);
- X return('!');
- X }
- X
- X if( c == '>' ) {
- X c=getit();
- X if( c == '=' ) return(GE);
- X if( c == '>' ) return(SHIFTR);
- X ungetit(c);
- X return('>');
- X }
- X
- X if( c == '<' ) {
- X c=getit();
- X if( c == '=' ) return(LE);
- X if( c == '<' ) return(SHIFTL);
- X ungetit(c);
- X return('<');
- X }
- X
- X if( c == '&' ) {
- X c=getit();
- X if( c == '&' ) return(AND);
- X ungetit(c);
- X return('&');
- X }
- X
- X if( c == '|' ) {
- X c=getit();
- X if( c == '|' ) return(OR);
- X ungetit(c);
- X return('|');
- X }
- X
- X return(c);
- X}
- X
- END_OF_FILE
- if test 14503 -ne `wc -c <'rhparse.c'`; then
- echo shar: \"'rhparse.c'\" unpacked with wrong size!
- fi
- # end of 'rhparse.c'
- fi
- echo shar: End of archive 2 \(of 2\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked both archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-